home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gdevpdf.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  27.2 KB  |  979 lines

  1. /* Copyright (C) 1996, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gdevpdf.c,v 1.21.2.1 2000/11/09 20:34:17 rayjj Exp $ */
  20. /* PDF-writing driver */
  21. #include "memory_.h"
  22. #include "string_.h"
  23. #include "gx.h"
  24. #include "gserrors.h"
  25. #include "gxdevice.h"
  26. #include "gdevpdfx.h"
  27. #include "gdevpdff.h"
  28. #include "gdevpdfg.h"        /* only for pdf_reset_graphics */
  29. #include "gdevpdfo.h"
  30.  
  31. /* Define the default language level and PDF compatibility level. */
  32. /* Acrobat 4 (PDF 1.3) is the default. */
  33. #define PSDF_VERSION_INITIAL psdf_version_ll3
  34. #define PDF_COMPATIBILITY_LEVEL_INITIAL 1.3
  35.  
  36. /* Define the names of the resource types. */
  37. private const char *const resource_type_names[] = {
  38.     pdf_resource_type_names
  39. };
  40.  
  41. /* Define the size of internal stream buffers. */
  42. /* (This is not a limitation, it only affects performance.) */
  43. #define sbuf_size 512
  44.  
  45. /* GC descriptors */
  46. private_st_pdf_page();
  47. gs_private_st_element(st_pdf_page_element, pdf_page_t, "pdf_page_t[]",
  48.               pdf_page_elt_enum_ptrs, pdf_page_elt_reloc_ptrs,
  49.               st_pdf_page);
  50. private_st_device_pdfwrite();
  51.  
  52. /* GC procedures */
  53. private 
  54. ENUM_PTRS_WITH(device_pdfwrite_enum_ptrs, gx_device_pdf *pdev)
  55. {
  56.     index -= gx_device_pdf_num_ptrs + gx_device_pdf_num_strings;
  57.     if (index < PDF_NUM_STD_FONTS)
  58.     ENUM_RETURN(pdev->std_fonts[index].font);
  59.     index -= PDF_NUM_STD_FONTS;
  60.     if (index < PDF_NUM_STD_FONTS)
  61.     ENUM_RETURN(pdev->std_fonts[index].pfd);
  62.     index -= PDF_NUM_STD_FONTS;
  63.     if (index < NUM_RESOURCE_TYPES * NUM_RESOURCE_CHAINS)
  64.     ENUM_RETURN(pdev->resources[index / NUM_RESOURCE_CHAINS].chains[index % NUM_RESOURCE_CHAINS]);
  65.     index -= NUM_RESOURCE_TYPES * NUM_RESOURCE_CHAINS;
  66.     if (index <= pdev->outline_depth)
  67.     ENUM_RETURN(pdev->outline_levels[index].first.action);
  68.     index -= pdev->outline_depth + 1;
  69.     if (index <= pdev->outline_depth)
  70.     ENUM_RETURN(pdev->outline_levels[index].last.action);
  71.     index -= pdev->outline_depth + 1;
  72.     ENUM_PREFIX(st_device_psdf, 0);
  73. }
  74. #define e1(i,elt) ENUM_PTR(i, gx_device_pdf, elt);
  75. gx_device_pdf_do_ptrs(e1)
  76. #undef e1
  77. #define e1(i,elt) ENUM_STRING_PTR(i + gx_device_pdf_num_ptrs, gx_device_pdf, elt);
  78. gx_device_pdf_do_strings(e1)
  79. #undef e1
  80. ENUM_PTRS_END
  81. private RELOC_PTRS_WITH(device_pdfwrite_reloc_ptrs, gx_device_pdf *pdev)
  82. {
  83.     RELOC_PREFIX(st_device_psdf);
  84. #define r1(i,elt) RELOC_PTR(gx_device_pdf,elt);
  85.     gx_device_pdf_do_ptrs(r1)
  86. #undef r1
  87. #define r1(i,elt) RELOC_STRING_PTR(gx_device_pdf,elt);
  88.     gx_device_pdf_do_strings(r1)
  89. #undef r1
  90.     {
  91.     int i, j;
  92.  
  93.     for (i = 0; i < PDF_NUM_STD_FONTS; ++i) {
  94.         RELOC_PTR(gx_device_pdf, std_fonts[i].font);
  95.         RELOC_PTR(gx_device_pdf, std_fonts[i].pfd);
  96.     }
  97.     for (i = 0; i < NUM_RESOURCE_TYPES; ++i)
  98.         for (j = 0; j < NUM_RESOURCE_CHAINS; ++j)
  99.         RELOC_PTR(gx_device_pdf, resources[i].chains[j]);
  100.     for (i = 0; i <= pdev->outline_depth; ++i) {
  101.         RELOC_PTR(gx_device_pdf, outline_levels[i].first.action);
  102.         RELOC_PTR(gx_device_pdf, outline_levels[i].last.action);
  103.     }
  104.     }
  105. }
  106. RELOC_PTRS_END
  107. /* Even though device_pdfwrite_finalize is the same as gx_device_finalize, */
  108. /* we need to implement it separately because st_composite_final */
  109. /* declares all 3 procedures as private. */
  110. private void
  111. device_pdfwrite_finalize(void *vpdev)
  112. {
  113.     gx_device_finalize(vpdev);
  114. }
  115.  
  116. /* Driver procedures */
  117. private dev_proc_open_device(pdf_open);
  118. private dev_proc_output_page(pdf_output_page);
  119. private dev_proc_close_device(pdf_close);
  120. /* Driver procedures defined in other files are declared in gdevpdfx.h. */
  121.  
  122. #ifndef X_DPI
  123. #  define X_DPI 720
  124. #endif
  125. #ifndef Y_DPI
  126. #  define Y_DPI 720
  127. #endif
  128.  
  129. const gx_device_pdf gs_pdfwrite_device =
  130. {std_device_dci_type_body(gx_device_pdf, 0, "pdfwrite",
  131.               &st_device_pdfwrite,
  132.               DEFAULT_WIDTH_10THS * X_DPI / 10,
  133.               DEFAULT_HEIGHT_10THS * Y_DPI / 10,
  134.               X_DPI, Y_DPI,
  135.               3, 24, 255, 255, 256, 256),
  136.  {pdf_open,
  137.   gx_upright_get_initial_matrix,
  138.   NULL,                /* sync_output */
  139.   pdf_output_page,
  140.   pdf_close,
  141.   gx_default_rgb_map_rgb_color,
  142.   gx_default_rgb_map_color_rgb,
  143.   gdev_pdf_fill_rectangle,
  144.   NULL,                /* tile_rectangle */
  145.   gdev_pdf_copy_mono,
  146.   gdev_pdf_copy_color,
  147.   NULL,                /* draw_line */
  148.   NULL,                /* get_bits */
  149.   gdev_pdf_get_params,
  150.   gdev_pdf_put_params,
  151.   NULL,                /* map_cmyk_color */
  152.   NULL,                /* get_xfont_procs */
  153.   NULL,                /* get_xfont_device */
  154.   NULL,                /* map_rgb_alpha_color */
  155.   gx_page_device_get_page_device,
  156.   NULL,                /* get_alpha_bits */
  157.   NULL,                /* copy_alpha */
  158.   NULL,                /* get_band */
  159.   NULL,                /* copy_rop */
  160.   gdev_pdf_fill_path,
  161.   gdev_pdf_stroke_path,
  162.   gdev_pdf_fill_mask,
  163.   NULL,                /* fill_trapezoid */
  164.   NULL,                /* fill_parallelogram */
  165.   NULL,                /* fill_triangle */
  166.   NULL,                /* draw_thin_line */
  167.   NULL,                /* begin_image */
  168.   NULL,                /* image_data */
  169.   NULL,                /* end_image */
  170.   gdev_pdf_strip_tile_rectangle,
  171.   NULL,                /* strip_copy_rop */
  172.   NULL,                /* get_clipping_box */
  173.   gdev_pdf_begin_typed_image,
  174.   NULL,                /* get_bits_rectangle */
  175.   NULL,                /* map_color_rgb_alpha */
  176.   NULL,                /* create_compositor */
  177.   NULL,                /* get_hardware_params */
  178.   gdev_pdf_text_begin
  179.  },
  180.  psdf_initial_values(PSDF_VERSION_INITIAL, 0 /*false */ ),  /* (!ASCII85EncodePages) */
  181.  PDF_COMPATIBILITY_LEVEL_INITIAL,  /* CompatibilityLevel */
  182.  -1,                /* EndPage */
  183.  1,                /* StartPage */
  184.  1 /*true*/,            /* Optimize */
  185.  0 /*false*/,            /* ParseDSCCommentsForDocInfo */
  186.  1 /*true*/,            /* ParseDSCComments */
  187.  0 /*false*/,            /* EmitDSCWarnings */
  188.  0 /*false*/,            /* CreateJobTicket */
  189.  0 /*false*/,            /* PreserveEPSInfo */
  190.  1 /*true*/,            /* AutoPositionEPSFiles */
  191.  1 /*true*/,            /* PreserveCopyPage */
  192.  0 /*false*/,            /* UsePrologue */
  193.  1 /*true*/,            /* ReAssignCharacters */
  194.  1 /*true*/,            /* ReEncodeCharacters */
  195.  1,                /* FirstObjectNumber */
  196.  0 /*false*/,            /* fill_overprint */
  197.  0 /*false*/,            /* stroke_overprint */
  198.  0,                /* overprint_mode */
  199.  gs_no_id,            /* halftone_id */
  200.  {gs_no_id, gs_no_id, gs_no_id, gs_no_id}, /* transfer_ids */
  201.  gs_no_id,            /* black_generation_id */
  202.  gs_no_id,            /* undercolor_removal_id */
  203.  pdf_compress_none,        /* compression */
  204.  {{0}},                /* xref */
  205.  {{0}},                /* asides */
  206.  {{0}},                /* streams */
  207.  {{0}},                /* pictures */
  208.  0,                /* open_font */
  209.  0 /*false*/,            /* use_open_font */
  210.  0,                /* embedded_encoding_id */
  211.  0,                /* next_id */
  212.  0,                /* Catalog */
  213.  0,                /* Info */
  214.  0,                /* Pages */
  215.  0,                /* outlines_id */
  216.  0,                /* next_page */
  217.  0,                /* contents_id */
  218.  PDF_IN_NONE,            /* context */
  219.  0,                /* contents_length_id */
  220.  0,                /* contents_pos */
  221.  NoMarks,            /* procsets */
  222.  {pdf_text_state_default},    /* text */
  223.  {{0}},                /* std_fonts */
  224.  {0},                /* space_char_ids */
  225.  {{0}},                /* text_rotation */
  226.  0,                /* pages */
  227.  0,                /* num_pages */
  228.  {
  229.      {
  230.      {0}}},            /* resources */
  231.  {0},                /* cs_Patterns */
  232.  0,                /* last_resource */
  233.  {
  234.      {
  235.      {0}}},            /* outline_levels */
  236.  0,                /* outline_depth */
  237.  0,                /* closed_outline_depth */
  238.  0,                /* outlines_open */
  239.  0,                /* articles */
  240.  0,                /* Dests */
  241.  0,                /* named_objects */
  242.  0                /* open_graphics */
  243. };
  244.  
  245. /* ---------------- Device open/close ---------------- */
  246.  
  247. /* Close and remove temporary files. */
  248. private int
  249. pdf_close_temp_file(gx_device_pdf *pdev, pdf_temp_file_t *ptf, int code)
  250. {
  251.     int err = 0;
  252.     FILE *file = ptf->file;
  253.  
  254.     /*
  255.      * ptf->strm == 0 or ptf->file == 0 is only possible if this procedure
  256.      * is called to clean up during initialization failure, but ptf->strm
  257.      * might not be open if it was finalized before the device was closed.
  258.      */
  259.     if (ptf->strm) {
  260.     if (s_is_valid(ptf->strm)) {
  261.         sflush(ptf->strm);
  262.         /* Prevent freeing the stream from closing the file. */
  263.         ptf->strm->file = 0;
  264.     } else
  265.         ptf->file = file = 0;    /* file was closed by finalization */
  266.     gs_free_object(pdev->pdf_memory, ptf->strm_buf,
  267.                "pdf_close_temp_file(strm_buf)");
  268.     ptf->strm_buf = 0;
  269.     gs_free_object(pdev->pdf_memory, ptf->strm,
  270.                "pdf_close_temp_file(strm)");
  271.     ptf->strm = 0;
  272.     }
  273.     if (file) {
  274.     err = ferror(file) | fclose(file);
  275.     unlink(ptf->file_name);
  276.     ptf->file = 0;
  277.     }
  278.     ptf->save_strm = 0;
  279.     return
  280.     (code < 0 ? code : err != 0 ? gs_note_error(gs_error_ioerror) : code);
  281. }
  282. private int
  283. pdf_close_files(gx_device_pdf * pdev, int code)
  284. {
  285.     code = pdf_close_temp_file(pdev, &pdev->pictures, code);
  286.     code = pdf_close_temp_file(pdev, &pdev->streams, code);
  287.     code = pdf_close_temp_file(pdev, &pdev->asides, code);
  288.     return pdf_close_temp_file(pdev, &pdev->xref, code);
  289. }
  290.  
  291. /* Reset the state of the current page. */
  292. private void
  293. pdf_reset_page(gx_device_pdf * pdev)
  294. {
  295.     pdev->contents_id = 0;
  296.     pdf_reset_graphics(pdev);
  297.     pdev->procsets = NoMarks;
  298.     memset(pdev->cs_Patterns, 0, sizeof(pdev->cs_Patterns));    /* simplest to create for each page */
  299.     {
  300.     static const pdf_text_state_t text_default = {
  301.         pdf_text_state_default
  302.     };
  303.  
  304.     pdev->text = text_default;
  305.     }
  306. }
  307.  
  308. /* Open a temporary file, with or without a stream. */
  309. private int
  310. pdf_open_temp_file(gx_device_pdf *pdev, pdf_temp_file_t *ptf)
  311. {
  312.     char fmode[4];
  313.  
  314.     strcpy(fmode, "w+");
  315.     strcat(fmode, gp_fmode_binary_suffix);
  316.     ptf->file =
  317.     gp_open_scratch_file(gp_scratch_file_name_prefix,
  318.                  ptf->file_name, fmode);
  319.     if (ptf->file == 0)
  320.     return_error(gs_error_invalidfileaccess);
  321.     return 0;
  322. }
  323. private int
  324. pdf_open_temp_stream(gx_device_pdf *pdev, pdf_temp_file_t *ptf)
  325. {
  326.     int code = pdf_open_temp_file(pdev, ptf);
  327.  
  328.     if (code < 0)
  329.     return code;
  330.     ptf->strm = s_alloc(pdev->pdf_memory, "pdf_open_temp_stream(strm)");
  331.     if (ptf->strm == 0)
  332.     return_error(gs_error_VMerror);
  333.     ptf->strm_buf = gs_alloc_bytes(pdev->pdf_memory, sbuf_size,
  334.                    "pdf_open_temp_stream(strm_buf)");
  335.     if (ptf->strm_buf == 0) {
  336.     gs_free_object(pdev->pdf_memory, ptf->strm,
  337.                "pdf_open_temp_stream(strm)");
  338.     ptf->strm = 0;
  339.     return_error(gs_error_VMerror);
  340.     }
  341.     swrite_file(ptf->strm, ptf->file, ptf->strm_buf, sbuf_size);
  342.     return 0;
  343. }
  344.  
  345. /* Initialize the IDs allocated at startup. */
  346. void
  347. pdf_initialize_ids(gx_device_pdf * pdev)
  348. {
  349.     gs_param_string nstr;
  350.     char buf[PDF_MAX_PRODUCER];
  351.  
  352.     pdev->next_id = pdev->FirstObjectNumber;
  353.  
  354.     /* Initialize the Catalog. */
  355.  
  356.     param_string_from_string(nstr, "{Catalog}");
  357.     pdf_create_named_dict(pdev, &nstr, &pdev->Catalog, 0L);
  358.  
  359.     /* Initialize the Info dictionary. */
  360.  
  361.     param_string_from_string(nstr, "{DocInfo}");
  362.     pdf_create_named_dict(pdev, &nstr, &pdev->Info, 0L);
  363.     pdf_store_default_Producer(buf);
  364.     cos_dict_put_c_key_string(pdev->Info, "/Producer", (byte *)buf,
  365.                   strlen(buf));
  366.  
  367.     /* Allocate the root of the pages tree. */
  368.  
  369.     pdf_create_named_dict(pdev, NULL, &pdev->Pages, 0L);
  370. }
  371.  
  372. /* Update the color mapping procedures after setting ProcessColorModel. */
  373. void
  374. pdf_set_process_color_model(gx_device_pdf * pdev)
  375. {
  376.     switch (pdev->color_info.num_components) {
  377.     case 1:
  378.     set_dev_proc(pdev, map_rgb_color, gx_default_gray_map_rgb_color);
  379.     set_dev_proc(pdev, map_color_rgb, gx_default_gray_map_color_rgb);
  380.     set_dev_proc(pdev, map_cmyk_color, NULL);
  381.     break;
  382.     case 3:
  383.     set_dev_proc(pdev, map_rgb_color, gx_default_rgb_map_rgb_color);
  384.     set_dev_proc(pdev, map_color_rgb, gx_default_rgb_map_color_rgb);
  385.     set_dev_proc(pdev, map_cmyk_color, NULL);
  386.     break;
  387.     case 4:
  388.     set_dev_proc(pdev, map_rgb_color, NULL);
  389.     set_dev_proc(pdev, map_color_rgb, cmyk_8bit_map_color_rgb);
  390.     set_dev_proc(pdev, map_cmyk_color, cmyk_8bit_map_cmyk_color);
  391.     break;
  392.     default:            /* can't happen */
  393.     DO_NOTHING;
  394.     }
  395. }
  396.  
  397. /*
  398.  * Reset the text state parameters to initial values.  This isn't a very
  399.  * good place for this procedure, but the alternatives seem worse.
  400.  */
  401. void
  402. pdf_reset_text(gx_device_pdf * pdev)
  403. {
  404.     pdev->text.character_spacing = 0;
  405.     pdev->text.font = NULL;
  406.     pdev->text.size = 0;
  407.     pdev->text.word_spacing = 0;
  408.     pdev->text.leading = 0;
  409.     pdev->text.use_leading = false;
  410. }
  411.  
  412. /* Open the device. */
  413. private int
  414. pdf_open(gx_device * dev)
  415. {
  416.     gx_device_pdf *const pdev = (gx_device_pdf *) dev;
  417.     gs_memory_t *mem = pdev->pdf_memory = gs_memory_stable(pdev->memory);
  418.     int code;
  419.  
  420.     if ((code = pdf_open_temp_file(pdev, &pdev->xref)) < 0 ||
  421.     (code = pdf_open_temp_stream(pdev, &pdev->asides)) < 0 ||
  422.     (code = pdf_open_temp_stream(pdev, &pdev->streams)) < 0 ||
  423.     (code = pdf_open_temp_stream(pdev, &pdev->pictures)) < 0
  424.     )
  425.     goto fail;
  426.     code = gdev_vector_open_file((gx_device_vector *) pdev, sbuf_size);
  427.     if (code < 0)
  428.     goto fail;
  429.     gdev_vector_init((gx_device_vector *) pdev);
  430.     pdev->fill_options = pdev->stroke_options = gx_path_type_optimize;
  431.     /* Set in_page so the vector routines won't try to call */
  432.     /* any vector implementation procedures. */
  433.     pdev->in_page = true;
  434.     /*
  435.      * pdf_initialize_ids allocates some named objects, so we must
  436.      * initialize the named objects list now.
  437.      */
  438.     pdev->named_objects = cos_dict_alloc(pdev, "pdf_open(named_objects)");
  439.     pdf_initialize_ids(pdev);
  440.     pdev->outlines_id = 0;
  441.     pdev->next_page = 0;
  442.     memset(pdev->space_char_ids, 0, sizeof(pdev->space_char_ids));
  443.     pdev->pages =
  444.     gs_alloc_struct_array(mem, initial_num_pages, pdf_page_t,
  445.                   &st_pdf_page_element, "pdf_open(pages)");
  446.     if (pdev->pages == 0) {
  447.     code = gs_error_VMerror;
  448.     goto fail;
  449.     }
  450.     memset(pdev->pages, 0, initial_num_pages * sizeof(pdf_page_t));
  451.     pdev->num_pages = initial_num_pages;
  452.     {
  453.     int i, j;
  454.  
  455.     for (i = 0; i < NUM_RESOURCE_TYPES; ++i)
  456.         for (j = 0; j < NUM_RESOURCE_CHAINS; ++j)
  457.         pdev->resources[i].chains[j] = 0;
  458.     }
  459.     pdev->outline_levels[0].first.id = 0;
  460.     pdev->outline_levels[0].left = max_int;
  461.     pdev->outline_levels[0].first.action = 0;
  462.     pdev->outline_levels[0].last.action = 0;
  463.     pdev->outline_depth = 0;
  464.     pdev->closed_outline_depth = 0;
  465.     pdev->outlines_open = 0;
  466.     pdev->articles = 0;
  467.     pdev->Dests = 0;
  468.     /* named_objects was initialized above */
  469.     pdev->open_graphics = 0;
  470.     pdf_reset_page(pdev);
  471.  
  472.     return 0;
  473.   fail:
  474.     return pdf_close_files(pdev, code);
  475. }
  476.  
  477. /* Detect I/O errors. */
  478. private int
  479. pdf_ferror(gx_device_pdf *pdev)
  480. {
  481.     fflush(pdev->file);
  482.     fflush(pdev->xref.file);
  483.     sflush(pdev->strm);
  484.     sflush(pdev->asides.strm);
  485.     sflush(pdev->streams.strm);
  486.     sflush(pdev->pictures.strm);
  487.     return ferror(pdev->file) || ferror(pdev->xref.file) ||
  488.     ferror(pdev->asides.file) || ferror(pdev->streams.file) ||
  489.     ferror(pdev->pictures.file);
  490. }
  491.  
  492. /* Compute the dominant text orientation of a page. */
  493. private int
  494. pdf_dominant_rotation(const pdf_text_rotation_t *ptr)
  495. {
  496.     int i, imax = 0;
  497.     long max_count = ptr->counts[0];
  498.     static const int angles[] = { pdf_text_rotation_angle_values };
  499.  
  500.     for (i = 1; i < countof(ptr->counts); ++i) {
  501.     long count = ptr->counts[i];
  502.  
  503.     if (count > max_count)
  504.         imax = i, max_count = count;
  505.     }
  506.     return angles[imax];
  507. }
  508.  
  509. /*
  510.  * Write and release the Cos objects for page-specific resources.
  511.  * We must write all the objects before freeing any of them, because
  512.  * they might refer to each other.
  513.  */
  514. private int
  515. pdf_write_resource_objects(gx_device_pdf *pdev, pdf_resource_type_t rtype)
  516. {
  517.     int j;
  518.  
  519.     /* Write objects. */
  520.     for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
  521.     pdf_resource_t *pres = pdev->resources[rtype].chains[j];
  522.  
  523.     for (; pres != 0; pres = pres->next)
  524.         if (!pres->named && !pres->object->written)
  525.         cos_write_object(pres->object, pdev);
  526.     }
  527.  
  528.     /* Free unnamed objects, which can't be used again. */
  529.     for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
  530.     pdf_resource_t **prev = &pdev->resources[rtype].chains[j];
  531.     pdf_resource_t *pres;
  532.  
  533.     while ((pres = *prev) != 0) {
  534.         if (pres->named) {    /* named, don't free */
  535.         prev = &pres->next;
  536.         } else {
  537.         cos_free(pres->object, "pdf_write_resource_objects");
  538.         pres->object = 0;
  539.         *prev = pres->next;
  540.         }
  541.     }
  542.     }
  543.  
  544.     return 0;
  545. }
  546.  
  547. /* Close the current page. */
  548. private int
  549. pdf_close_page(gx_device_pdf * pdev)
  550. {
  551.     int page_num = ++(pdev->next_page);
  552.     pdf_page_t *page;
  553.  
  554.     /*
  555.      * If the very first page is blank, we need to open the document
  556.      * before doing anything else.
  557.      */
  558.  
  559.     pdf_open_document(pdev);
  560.     pdf_close_contents(pdev, true);
  561.  
  562.     /*
  563.      * We can't write the page object or the annotations array yet, because
  564.      * later pdfmarks might add elements to them.  Write the other objects
  565.      * that the page references, and record what we'll need later.
  566.      *
  567.      * Start by making sure the pages array element exists.
  568.      */
  569.  
  570.     pdf_page_id(pdev, page_num);
  571.     page = &pdev->pages[page_num - 1];
  572.     page->MediaBox.x = (int)(pdev->MediaSize[0]);
  573.     page->MediaBox.y = (int)(pdev->MediaSize[1]);
  574.     page->procsets = pdev->procsets;
  575.     page->contents_id = pdev->contents_id;
  576.  
  577.     /* Write out any resource dictionaries. */
  578.  
  579.     {
  580.     int i;
  581.  
  582.     for (i = 0; i < resourceFont; ++i) {
  583.         bool any = false;
  584.         stream *s;
  585.         int j;
  586.  
  587.         for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
  588.         pdf_resource_t *pres = pdev->resources[i].chains[j];
  589.  
  590.         for (; pres != 0; pres = pres->next) {
  591.             if (pres->used_on_page) {
  592.             long id = pres->object->id;
  593.  
  594.             if (!any) {
  595.                 page->resource_ids[i] = pdf_begin_obj(pdev);
  596.                 s = pdev->strm;
  597.                 pputs(s, "<<");
  598.                 any = true;
  599.             }
  600.             pprintld2(s, "/R%ld\n%ld 0 R", id, id);
  601.             }
  602.         }
  603.         }
  604.         if (any) {
  605.         pputs(s, ">>\n");
  606.         pdf_end_obj(pdev);
  607.         pdf_write_resource_objects(pdev, i);
  608.         }
  609.     }
  610.     }
  611.  
  612.     /* Write out Functions. */
  613.  
  614.     pdf_write_resource_objects(pdev, resourceFunction);
  615.  
  616.     /* Record references to just those fonts used on this page. */
  617.  
  618.     {
  619.     bool any = false;
  620.     stream *s;
  621.     int j;
  622.  
  623.     for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
  624.         pdf_font_t **prev =
  625.         (pdf_font_t **)&pdev->resources[resourceFont].chains[j];
  626.         pdf_font_t *font;
  627.  
  628.         while ((font = *prev) != 0) {
  629.         if (font->used_on_page) {
  630.             if (!any) {
  631.             page->fonts_id = pdf_begin_obj(pdev);
  632.             s = pdev->strm;
  633.             pputs(s, "<<");
  634.             any = true;
  635.             }
  636.             pprints1(s, "/%s", font->frname);
  637.             pprintld1(s, "\n%ld 0 R", font->object->id);
  638.             font->used_on_page = false;
  639.         }
  640.         if (font->skip) {
  641.             /* The font was already written and freed. */
  642.             *prev = font->next;
  643.         } else
  644.             prev = &font->next;
  645.         }
  646.     }
  647.     if (any) {
  648.         pputs(s, ">>\n");
  649.         pdf_end_obj(pdev);
  650.     }
  651.     }
  652.     /*
  653.      * When Acrobat Reader 3 prints a file containing a Type 3 font with a
  654.      * non-standard Encoding, it apparently only emits the subset of the
  655.      * font actually used on the page.  Thus, if the "Download Fonts Once"
  656.      * option is selected, characters not used on the page where the font
  657.      * first appears will not be defined, and hence will print as blank if
  658.      * used on subsequent pages.  Thus, we can't allow a Type 3 font to
  659.      * add additional characters on subsequent pages.
  660.      */
  661.     if (pdev->CompatibilityLevel <= 1.2)
  662.     pdev->use_open_font = false;
  663.  
  664.     /* Accumulate text rotation. */
  665.  
  666.     page->text_rotation.Rotate =
  667.     (pdev->params.AutoRotatePages == arp_PageByPage ?
  668.      pdf_dominant_rotation(&page->text_rotation) : -1);
  669.     {
  670.     int i;
  671.  
  672.     for (i = 0; i < countof(page->text_rotation.counts); ++i)
  673.         pdev->text_rotation.counts[i] += page->text_rotation.counts[i];
  674.     }
  675.  
  676.     pdf_reset_page(pdev);
  677.     return (pdf_ferror(pdev) ? gs_note_error(gs_error_ioerror) : 0);
  678. }
  679.  
  680. /* Write the page object. */
  681. private int
  682. pdf_write_page(gx_device_pdf *pdev, int page_num)
  683. {
  684.     long page_id = pdf_page_id(pdev, page_num);
  685.     pdf_page_t *page = &pdev->pages[page_num - 1];
  686.     stream *s;
  687.  
  688.     pdf_open_obj(pdev, page_id);
  689.     s = pdev->strm;
  690.     pprintd2(s, "<</Type/Page/MediaBox [0 0 %d %d]\n",
  691.          page->MediaBox.x, page->MediaBox.y);
  692.     if (page->text_rotation.Rotate >= 0)
  693.     pprintd1(s, "/Rotate %d", page->text_rotation.Rotate);
  694.     pprintld1(s, "/Parent %ld 0 R\n", pdev->Pages->id);
  695.     pputs(s, "/Resources<</ProcSet[/PDF");
  696.     if (page->procsets & ImageB)
  697.     pputs(s, " /ImageB");
  698.     if (page->procsets & ImageC)
  699.     pputs(s, " /ImageC");
  700.     if (page->procsets & ImageI)
  701.     pputs(s, " /ImageI");
  702.     if (page->procsets & Text)
  703.     pputs(s, " /Text");
  704.     pputs(s, "]\n");
  705.     {
  706.     int i;
  707.  
  708.     for (i = 0; i < resourceFont; ++i)
  709.         if (page->resource_ids[i]) {
  710.         pprints1(s, "/%s ", resource_type_names[i]);
  711.         pprintld1(s, "%ld 0 R\n", page->resource_ids[i]);
  712.         }
  713.     }
  714.     if (page->fonts_id)
  715.     pprintld1(s, "/Font %ld 0 R\n", page->fonts_id);
  716.     pputs(s, ">>\n");
  717.  
  718.     /* Write out the annotations array if any. */
  719.  
  720.     if (page->Annots) {
  721.     pputs(s, "/Annots");
  722.     COS_WRITE(page->Annots, pdev);
  723.     COS_FREE(page->Annots, "pdf_write_page(Annots)");
  724.     page->Annots = 0;
  725.     }
  726.     if (page->contents_id == 0)
  727.     pputs(s, "/Contents []\n");
  728.     else
  729.     pprintld1(s, "/Contents %ld 0 R\n", page->contents_id);
  730.  
  731.     /* Write any elements stored by pdfmarks. */
  732.  
  733.     cos_dict_elements_write(page->Page, pdev);
  734.  
  735.     pputs(s, ">>\n");
  736.     pdf_end_obj(pdev);
  737.     return 0;
  738. }
  739.  
  740. /* Wrap up ("output") a page. */
  741. private int
  742. pdf_output_page(gx_device * dev, int num_copies, int flush)
  743. {
  744.     gx_device_pdf *const pdev = (gx_device_pdf *) dev;
  745.     int code = pdf_close_page(pdev);
  746.  
  747.     return (code < 0 ? code :
  748.         pdf_ferror(pdev) ? gs_note_error(gs_error_ioerror) :
  749.         gx_finish_output_page(dev, num_copies, flush));
  750. }
  751.  
  752. /* Close the device. */
  753. private int
  754. pdf_close(gx_device * dev)
  755. {
  756.     gx_device_pdf *const pdev = (gx_device_pdf *) dev;
  757.     gs_memory_t *mem = pdev->pdf_memory;
  758.     stream *s;
  759.     FILE *tfile = pdev->xref.file;
  760.     long xref;
  761.     long resource_pos;
  762.     long Catalog_id = pdev->Catalog->id, Info_id = pdev->Info->id,
  763.     Pages_id = pdev->Pages->id;
  764.     long Threads_id = 0;
  765.     bool partial_page = (pdev->contents_id != 0 && pdev->next_page != 0);
  766.  
  767.     /*
  768.      * If this is an EPS file, or if the file didn't end with a showpage for
  769.      * some other reason, or if the file has produced no marks at all, we
  770.      * need to tidy up a little so as not to produce illegal PDF.  However,
  771.      * if there is at least one complete page, we discard any leftover
  772.      * marks.
  773.      */
  774.     if (pdev->next_page == 0)
  775.     pdf_open_document(pdev);
  776.     if (pdev->contents_id != 0)
  777.     pdf_close_page(pdev);
  778.  
  779.     /* Write the page objects. */
  780.  
  781.     {
  782.     int i;
  783.  
  784.     for (i = 1; i <= pdev->next_page; ++i)
  785.         pdf_write_page(pdev, i);
  786.     }
  787.  
  788.     /* Write the font resources and related resources. */
  789.  
  790.     pdf_write_font_resources(pdev);
  791.  
  792.     /* Create the Pages tree. */
  793.  
  794.     pdf_open_obj(pdev, Pages_id);
  795.     s = pdev->strm;
  796.     pputs(s, "<< /Type /Pages /Kids [\n");
  797.     /* Omit the last page if it was incomplete. */
  798.     if (partial_page)
  799.     --(pdev->next_page);
  800.     {
  801.     int i;
  802.  
  803.     for (i = 0; i < pdev->next_page; ++i)
  804.         pprintld1(s, "%ld 0 R\n", pdev->pages[i].Page->id);
  805.     }
  806.     pprintd1(s, "] /Count %d\n", pdev->next_page);
  807.     if (pdev->params.AutoRotatePages == arp_All)
  808.     pprintd1(s, "/Rotate %d\n",
  809.          pdf_dominant_rotation(&pdev->text_rotation));
  810.     cos_dict_elements_write(pdev->Pages, pdev);
  811.     pputs(s, ">>\n");
  812.     pdf_end_obj(pdev);
  813.  
  814.     /* Close outlines and articles. */
  815.  
  816.     if (pdev->outlines_id != 0) {
  817.     /* depth > 0 is only possible for an incomplete outline tree. */
  818.     while (pdev->outline_depth > 0)
  819.         pdfmark_close_outline(pdev);
  820.     pdfmark_close_outline(pdev);
  821.     pdf_open_obj(pdev, pdev->outlines_id);
  822.     pprintd1(s, "<< /Count %d", pdev->outlines_open);
  823.     pprintld2(s, " /First %ld 0 R /Last %ld 0 R >>\n",
  824.           pdev->outline_levels[0].first.id,
  825.           pdev->outline_levels[0].last.id);
  826.     pdf_end_obj(pdev);
  827.     }
  828.     if (pdev->articles != 0) {
  829.     pdf_article_t *part;
  830.  
  831.     /* Write the remaining information for each article. */
  832.     for (part = pdev->articles; part != 0; part = part->next)
  833.         pdfmark_write_article(pdev, part);
  834.     }
  835.  
  836.     /* Write named destinations.  (We can't free them yet.) */
  837.  
  838.     if (pdev->Dests)
  839.     COS_WRITE_OBJECT(pdev->Dests, pdev);
  840.  
  841.     /* Write the Catalog. */
  842.  
  843.     /*
  844.      * The PDF specification requires Threads to be an indirect object.
  845.      * Write the threads now, if any.
  846.      */
  847.     if (pdev->articles != 0) {
  848.     pdf_article_t *part;
  849.  
  850.     Threads_id = pdf_begin_obj(pdev);
  851.     s = pdev->strm;
  852.     pputs(s, "[ ");
  853.     while ((part = pdev->articles) != 0) {
  854.         pdev->articles = part->next;
  855.         pprintld1(s, "%ld 0 R\n", part->contents->id);
  856.         COS_FREE(part->contents, "pdf_close(article contents)");
  857.         gs_free_object(mem, part, "pdf_close(article)");
  858.     }
  859.     pputs(s, "]\n");
  860.     pdf_end_obj(pdev);
  861.     }
  862.     pdf_open_obj(pdev, Catalog_id);
  863.     s = pdev->strm;
  864.     pputs(s, "<<");
  865.     pprintld1(s, "/Type /Catalog /Pages %ld 0 R\n", Pages_id);
  866.     if (pdev->outlines_id != 0)
  867.     pprintld1(s, "/Outlines %ld 0 R\n", pdev->outlines_id);
  868.     if (Threads_id)
  869.     pprintld1(s, "/Threads %ld 0 R\n", Threads_id);
  870.     if (pdev->Dests)
  871.     pprintld1(s, "/Dests %ld 0 R\n", pdev->Dests->id);
  872.     cos_dict_elements_write(pdev->Catalog, pdev);
  873.     pputs(s, ">>\n");
  874.     pdf_end_obj(pdev);
  875.     if (pdev->Dests) {
  876.     COS_FREE(pdev->Dests, "pdf_close(Dests)");
  877.     pdev->Dests = 0;
  878.     }
  879.  
  880.     /* Prevent writing special named objects twice. */
  881.  
  882.     pdev->Catalog->id = 0;
  883.     /*pdev->Info->id = 0;*/    /* Info should get written */
  884.     pdev->Pages->id = 0;
  885.     {
  886.     int i;
  887.  
  888.     for (i = 0; i < pdev->num_pages; ++i)
  889.         if (pdev->pages[i].Page)
  890.         pdev->pages[i].Page->id = 0;
  891.     }
  892.  
  893.     /*
  894.      * Write the definitions of the named objects.
  895.      * Note that this includes Form XObjects created by BP/EP, named PS
  896.      * XObjects, and eventually images named by NI.
  897.      */
  898.  
  899.     cos_dict_objects_write(pdev->named_objects, pdev);
  900.  
  901.     /* Copy the resources into the main file. */
  902.  
  903.     s = pdev->strm;
  904.     resource_pos = stell(s);
  905.     sflush(pdev->asides.strm);
  906.     {
  907.     FILE *rfile = pdev->asides.file;
  908.     long res_end = ftell(rfile);
  909.  
  910.     fseek(rfile, 0L, SEEK_SET);
  911.     pdf_copy_data(s, rfile, res_end);
  912.     }
  913.  
  914.     /* Write the cross-reference section. */
  915.  
  916.     xref = pdf_stell(pdev);
  917.     if (pdev->FirstObjectNumber == 1)
  918.     pprintld1(s, "xref\n0 %ld\n0000000000 65535 f \n",
  919.           pdev->next_id);
  920.     else
  921.     pprintld2(s, "xref\n0 1\n0000000000 65535 f \n%ld %ld\n",
  922.           pdev->FirstObjectNumber,
  923.           pdev->next_id - pdev->FirstObjectNumber);
  924.     fseek(tfile, 0L, SEEK_SET);
  925.     {
  926.     long i;
  927.  
  928.     for (i = pdev->FirstObjectNumber; i < pdev->next_id; ++i) {
  929.         ulong pos;
  930.         char str[21];
  931.  
  932.         fread(&pos, sizeof(pos), 1, tfile);
  933.         if (pos & ASIDES_BASE_POSITION)
  934.         pos += resource_pos - ASIDES_BASE_POSITION;
  935.         sprintf(str, "%010ld 00000 n \n", pos);
  936.         pputs(s, str);
  937.     }
  938.     }
  939.  
  940.     /* Write the trailer. */
  941.  
  942.     pputs(s, "trailer\n");
  943.     pprintld3(s, "<< /Size %ld /Root %ld 0 R /Info %ld 0 R\n",
  944.           pdev->next_id, Catalog_id, Info_id);
  945.     pputs(s, ">>\n");
  946.     pprintld1(s, "startxref\n%ld\n%%%%EOF\n", xref);
  947.  
  948.     /* Release the resource records. */
  949.  
  950.     {
  951.     pdf_resource_t *pres;
  952.     pdf_resource_t *prev;
  953.  
  954.     for (prev = pdev->last_resource; (pres = prev) != 0;) {
  955.         prev = pres->prev;
  956.         gs_free_object(mem, pres, "pdf_resource_t");
  957.     }
  958.     pdev->last_resource = 0;
  959.     }
  960.  
  961.     /* Free named objects. */
  962.  
  963.     cos_dict_objects_delete(pdev->named_objects);
  964.     COS_FREE(pdev->named_objects, "pdf_close(named_objects)");
  965.     pdev->named_objects = 0;
  966.  
  967.     /* Wrap up. */
  968.  
  969.     gs_free_object(mem, pdev->pages, "pages");
  970.     pdev->pages = 0;
  971.     pdev->num_pages = 0;
  972.  
  973.     {
  974.     int code = gdev_vector_close_file((gx_device_vector *) pdev);
  975.  
  976.     return pdf_close_files(pdev, code);
  977.     }
  978. }
  979.